package org.derusse.cycle.model;

import java.util.ArrayList;
import java.util.List;

import org.derusse.cycle.CycleMeterApplication;
import org.derusse.cycle.database.DatabaseHelper;
import org.derusse.cycle.database.StatsTable;
import org.derusse.cycle.event.LocationStatsListener;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

public class Stats implements LocationListener {
	private Location lastLocation;
	private LocationManager locationManager;
	private DatabaseHelper databaseHelper;
	
	private List<LocationStatsListener> statsListeners = new ArrayList<LocationStatsListener>();

	private double trace = 0;
	private double avg1 = 0;
	private double avg10 = 0;
	private double tilt = 0;

	public Stats(CycleMeterApplication application) {
		this.locationManager = application.getLocationManager();
		this.databaseHelper = application.getDatabaseHelper();
	}

	public void addListener(LocationStatsListener listener) {
		statsListeners.add(listener);
	}

	public void removeListener(LocationStatsListener listener) {
		statsListeners.remove(listener);
	}

	public void Start() {
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
				5000, 20, this);
	}

	public void Stop() {
		locationManager.removeUpdates(this);
	}
	
	private void SaveStats(Location location)
	{
		if(location.hasAccuracy() && location.getAccuracy()>35) return;
		if(location.hasSpeed() && location.getSpeed()>100) return;
		if (this.lastLocation == null)
		{
			this.lastLocation = location;
			return;
		}

		float distance = this.lastLocation.distanceTo(location);
		if(distance< 10 ) return;

		this.trace += distance;
		
		SQLiteDatabase db = null;
		Cursor cursor = null;
		try {
			db = this.databaseHelper.getWritableDatabase();
			StatsTable.Clean(db);
			StatsTable.Insert(db, location, distance, trace);
			
			cursor = StatsTable.SelectAvg(db, 60);
			if (cursor.moveToFirst()) {
				if (cursor.getLong(1) != cursor.getLong(0)) {
					this.avg1 = 1000 * cursor.getFloat(2)
					/ (cursor.getLong(1) - cursor.getLong(0));
				}
			}
			cursor.close();
			cursor = StatsTable.SelectAvg(db, 600);
			if (cursor.moveToFirst()) {
				if (cursor.getLong(1) != cursor.getLong(0)) {
					this.avg10 = 1000 * cursor.getFloat(2)
							/ (cursor.getLong(1) - cursor.getLong(0));
				}
			}
			cursor.close();
			
			cursor = StatsTable.SelectTilt(db, this.trace);
			if (cursor.moveToFirst()) {
				double dst = this.trace - cursor.getLong(1);
				if (dst < 5) {
					this.tilt = 0;
				} else {
					float alt = cursor.getFloat(0); 
					double climb = location.getAltitude()
							- alt;
					double tilt = climb * 100 / dst;
					if(tilt<70) this.tilt = tilt;
				}
			}
			
		} finally {
			if (cursor != null)
				cursor.close();
			if (db != null)
				db.close();
		}
	}

	public void onLocationChanged(Location location) {
		if(location.hasAccuracy() && location.getAccuracy()>30) return;
		
		this.SaveStats(location);
		this.lastLocation = location;
		
		int countListener = this.statsListeners.size();
		for (int i = 0; i < countListener; i++) {
			this.statsListeners.get(i).onStatsChanged();
		}
	}

	public void onProviderDisabled(String provider) {
	}

	public void onProviderEnabled(String provider) {
	}

	public void onStatusChanged(String provider, int status, Bundle extraBundle) {
	}

	public void onGpsChanged(int oldStatus, int newStatus) {
	}
	
	public String getTiltFormat() {
		return String.format("%.01f", this.tilt);
	}

	public String getAvg1Format() {
		return String.format("%.01f", this.avg1 * 3.6);
	}

	public String getAvg10Format() {
		return String.format("%.01f", this.avg10 * 3.6);
	}

}